﻿#include <chrono>
#include "PLFinder.h"

void PLFinderBase::clear()
{
    exhaNum1st = exhaNum2nd = exhaSum = 0;
    findSteps = 0;
	mapClear();
}

// 记录最大，第二大递归数，递归总数
void PLFinderBase::recExhaNum(unsigned int n)
{
    exhaSum += n;
	if (n > exhaNum1st)
    {
        exhaNum2nd = exhaNum1st;
        exhaNum1st = n;
    }
	else if (n != exhaNum1st && n > exhaNum2nd)
		exhaNum2nd = n;
}

//  完成返回0，未完成返回1，有错误返回2，用户中断返回3
int PLFinderBase::exec2()
{
	try
	{
        int oldSteps;
		do
		{
			// 扫描一遍，如果有改动则继续
            oldSteps = findSteps;
            // 按列解一遍
            procCol = true;
            execALoop(cols, &PLFinderBase::colPoint, rows, colFlags);
            // 按行解一遍
            procCol = false;
            execALoop(rows, &PLFinderBase::rowPoint, cols, rowFlags);
		} while (findSteps > oldSteps);     // 有解出的格子，继续
	}
	catch(Err e)
	{
		return e == Err::UserBreak ? 3 : 2;
	}
	return findSteps == cols * rows ? 0 : 1;
}

int PLFinderBase::exec(bool needClear, int)
{
	if (needClear) clear();

	using namespace std::chrono;
    auto start_time = high_resolution_clock::now();
	int res = exec2();
    auto end_time = high_resolution_clock::now();
    timeUsec = duration_cast<microseconds>(end_time - start_time).count();

	return res;
}

// 按行或列处理一遍（多线程）
void PLFinderMT::execALoop(int n, PointPtr ptr, int len, Flags flags[])
{
    typedef std::pair<int, unsigned int> FinderRes;

    auto lineThread = [l = len](Cell* wl, Flags& fs)
    {
        LineFinder lineFinder;
        int m = lineFinder.procALine(wl, l, fs);
        return FinderRes{m, lineFinder.exhaNum};
    };

    std::vector<std::future<FinderRes>> futures(n);
	for (int i = 0; i < n; ++i)
        if (flags[i].needProc)
            futures[i] = pthrPool->commit(lineThread, (this->*ptr)(i, 0), std::ref(flags[i]));     // 传引用 std::ref(flags[i])
	for (int i = 0; i < n; ++i)
		if (futures[i].valid())
		{
			auto [steps, exhaNum] = futures[i].get();     // c++17 结构化绑定
            if (steps > 0) (this->*ptr)(i, 1);  // 回写
            findSteps += steps;
            recExhaNum(exhaNum);
            if (needCallback && callback(i, procCol, steps, exhaNum)) throw Err::UserBreak;
		}
}

int PLFinderMT::exec(bool needClear, int thrNum)
{
	//  建立线程池
	pthrPool = std::make_unique<ThreadPool>(thrNum);
    threadNum = pthrPool->size();

    return PLFinderBase::exec(needClear);
}

// 按行或列处理一遍（单线程）
void PLFinderST::execALoop(int n, PointPtr ptr, int len, Flags flags[])
{
	for (int i = 0; i < n; ++i)
        if (flags[i].needProc)
		{
            int steps = procALine((this->*ptr)(i, 0), len, flags[i]);
            if (steps > 0) (this->*ptr)(i, 1);  // 回写
            findSteps += steps;
            recExhaNum(exhaNum);
            if (needCallback && callback(i, procCol, steps, exhaNum)) throw Err::UserBreak;
		}
}




